#ifndef _CTRIANGLE3D_H_
#define _CTRIANGLE3D_H_

#include "StdDefs.h"
#include "CMathFixed.h"
#include "CVector3d.h"
#include "CLineSegment3d.h"
#include "CSpace.h"
#include "CWinding.h"
#include "CSphere.h"
#include "CTriangle2d.h"

class CTriangle3d
{
public:
	CTriangle3d();
	CTriangle3d( const CVector3d& v0, const CVector3d& v1, const CVector3d& v2 );
	~CTriangle3d();

	static boolean					Sweep( const CVector3d& t0v0, const CVector3d& t0v1, const CVector3d& t0v2,  
										   const CVector3d& t1v0, const CVector3d& t1v1, const CVector3d& t1v2, 
										   const CVector3d& v1, const CVector3d& v2, fixed &t );

	static boolean					Sweep( const CVector3d& tv0, const CVector3d& tv1, const CVector3d& tv2,
										   const CVector3d& pos, fixed radius,
										   const CVector3d& v1, const CVector3d& v2, fixed &t );

	static boolean					Sweep( const CVector3d& tv0, const CVector3d& tv1, const CVector3d& tv2,
										   const CVector3d& segA, const CVector3d& segB, fixed radius,
										   const CVector3d& v1, const CVector3d& v2, fixed &t );
	
	static boolean					Intersects( const CVector3d& tv0, const CVector3d& tv1, const CVector3d& tv2,
												const CPlane& plane ); // triangle - plane

	static boolean					Intersects( const CVector3d& t0v0, const CVector3d& t0v1, const CVector3d& t0v2,
												const CVector3d& t1v0, const CVector3d& t1v1, const CVector3d& t1v2 ); // triangle - triangle

	static boolean					Intersects( const CVector3d& tv0, const CVector3d& tv1, const CVector3d& tv2, 
												const CVector3d& v0, const CVector3d& v1, fixed &u ); // triangle - segment

	static boolean					Intersects( const CVector3d& tv0, const CVector3d& tv1, const CVector3d& tv2,
												const CVector3d& pos, fixed radius );

	static boolean					Intersects( const CVector3d& tv0, const CVector3d& tv1, const CVector3d& tv2,
												const CVector3d& segA, const CVector3d& segB, fixed radius, fixed &u );

	static void						ClosestPoint( const CVector3d& tv0, const CVector3d& tv1, const CVector3d& tv2, const CVector3d& pt, CVector3d& p );

	static void						ClosestPoint( const CVector3d& tv0, const CVector3d& tv1, const CVector3d& tv2, 
												  const CVector3d& v0,  const CVector3d& v1, CVector3d& c1, CVector3d& c2, fixed* u = NULL );

    static CSpace::Relativity		DetermineSpace( const CVector3d& tv0, const CVector3d& tv1, const CVector3d& tv2, const CVector3d& pt );

	static void						Barycentric( const CVector3d& tv0, const CVector3d& tv1, const CVector3d& tv2, const CVector3d& p, fixed &u, fixed &v, fixed &w );

	static void						ProjectToAAPlane( CPlane::AxisAlignedPlane aaplane, const CVector3d& v0, const CVector3d& v1, const CVector3d& v2,
													  CVector2d& outv0, CVector2d& outV1, CVector2d& outV2 );

	boolean							Sweep( const CTriangle3d& t2, const CVector3d& v1, const CVector3d& v2, fixed &u ) const;
	boolean							Intersects( const CPlane& plane ) const;
	boolean							Intersects( const CTriangle3d& t ) const;
	boolean							Intersects( const CVector3d& v0, const CVector3d& v1, fixed& u ) const;
	boolean							Intersects( const CLineSegment3d& seg, fixed &u ) const;

	void							ClosestPoint( const CVector3d& pt, CVector3d& p ) const;
	void							ClosestPoint( const CVector3d& v0, const CVector3d& v1, CVector3d& c1, CVector3d& c2, fixed *u = NULL ) const;
	
	CSpace::Relativity				DetermineSpace( const CVector3d& pt ) const;

	void							Barycentric( const CVector3d& p, fixed &u, fixed &v, fixed &w ) const;

	boolean							IsIsoceles() const;
	boolean							IsEquilateral() const;
	
	fixed							GetArea() const;
    void							ComputePlane( CPlane& outPlane ) const;
	void							ComputeNormal( CVector3d& outNormal ) const;							

	void							ComputeIncenter( CVector3d& outPoint ) const;
	void							ComputeInsphere( CSphere& outSphere ) const;

	void							ComputeCircumcenter( CVector3d& outPoint ) const;
	void							ComputerCircumsphere( CSphere& outSphere ) const;

	CWinding::WindingOrder			GetWinding() const;

	void							ProjectToAAPlane( CPlane::AxisAlignedPlane aaplane, CTriangle2d& outTriangle );	
		
	CVector3d						m_v0;
	CVector3d						m_v1;
	CVector3d						m_v2;

private:						

};


inline
void CTriangle3d::ProjectToAAPlane( CPlane::AxisAlignedPlane aaplane, const CVector3d& v0, const CVector3d& v1, const CVector3d& v2,
									CVector2d& outv0, CVector2d& outv1, CVector2d& outv2 )
{
	CPlane::ProjectToAAPlane( aaplane, v0, outv0 );
	CPlane::ProjectToAAPlane( aaplane, v1, outv1 );
	CPlane::ProjectToAAPlane( aaplane, v2, outv2 );
}


inline
boolean CTriangle3d::Sweep( const CTriangle3d& t2, const CVector3d& v1, const CVector3d& v2, fixed& t ) const
{
	return Sweep( this->m_v0, this->m_v1, this->m_v2, t2.m_v0, t2.m_v1, t2.m_v2, v2, v2, t );
}

inline
boolean CTriangle3d::Intersects( const CPlane& plane ) const
{
	return Intersects( this->m_v0, this->m_v1, this->m_v2, plane );
}

inline
boolean CTriangle3d::Intersects( const CTriangle3d& t ) const
{
	return Intersects( this->m_v0, this->m_v1, this->m_v2, t.m_v0, t.m_v1, t.m_v2 );
}

inline
boolean CTriangle3d::Intersects( const CLineSegment3d& seg, fixed& u ) const
{
	return Intersects( this->m_v0, this->m_v1, this->m_v2, seg.m_v0, seg.m_v1, u );
}


inline
boolean CTriangle3d::Intersects( const CVector3d& v0, const CVector3d& v1, fixed& u ) const
{
	return Intersects( this->m_v0, this->m_v1, this->m_v2, v0, v1, u );
}

inline
void CTriangle3d::ClosestPoint( const CVector3d& pt, CVector3d& p ) const
{
	ClosestPoint( m_v0, m_v1, m_v2, pt, p );
}


inline
void CTriangle3d::ClosestPoint( const CVector3d& v0, const CVector3d& v1, CVector3d& c1, CVector3d& c2, fixed *u ) const
{
	ClosestPoint( m_v0, m_v1, m_v2, v0, v1, c1, c2, u );
}

inline
CSpace::Relativity CTriangle3d::DetermineSpace( const CVector3d& pt ) const
{
	return DetermineSpace( this->m_v0, this->m_v1, this->m_v2, pt );
}


inline
void CTriangle3d::Barycentric( const CVector3d& p, fixed &u, fixed &v, fixed &w ) const
{
	Barycentric( m_v0, m_v1, m_v2, p, u, v, w );
}


inline
fixed CTriangle3d::GetArea() const
{
	ASSERT( FALSE );
}


inline
void CTriangle3d::ComputeNormal( CVector3d& outNormal ) const
{
	ASSERT ( FALSE );
}


inline
void CTriangle3d::ComputePlane( CPlane& outPlane ) const
{
	ASSERT ( FALSE );
}


inline
CWinding::WindingOrder CTriangle3d::GetWinding() const
{
	ASSERT ( FALSE );
}


inline
void CTriangle3d::ProjectToAAPlane( CPlane::AxisAlignedPlane aaplane, CTriangle2d& outTriangle )
{
	ProjectToAAPlane( aaplane, m_v0, m_v1, m_v2, outTriangle.m_v0, outTriangle.m_v1, outTriangle.m_v2 );
}

#endif //_CTRIANGLE3D_H_